package roaring
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"strconv"
"github.com/RoaringBitmap/roaring/v2/internal"
"github.com/bits-and-blooms/bitset"
)
type Bitmap struct {
highlowcontainer roaringArray
}
func (rb *Bitmap ) ToBase64 () (string , error ) {
buf := new (bytes .Buffer )
_ , err := rb .WriteTo (buf )
return base64 .StdEncoding .EncodeToString (buf .Bytes ()), err
}
func (rb *Bitmap ) FromBase64 (str string ) (int64 , error ) {
data , err := base64 .StdEncoding .DecodeString (str )
if err != nil {
return 0 , err
}
buf := bytes .NewBuffer (data )
return rb .ReadFrom (buf )
}
func (rb *Bitmap ) WriteTo (stream io .Writer ) (int64 , error ) {
return rb .highlowcontainer .writeTo (stream )
}
func (rb *Bitmap ) ToBytes () ([]byte , error ) {
return rb .highlowcontainer .toBytes ()
}
const (
wordSize = uint64 (64 )
log2WordSize = uint64 (6 )
capacity = ^uint64 (0 )
bitmapContainerSize = (1 << 16 ) / 64
)
func (rb *Bitmap ) DenseSize () uint64 {
if rb .highlowcontainer .size () == 0 {
return 0
}
maximum := 1 + uint64 (rb .Maximum ())
if maximum > (capacity - wordSize + 1 ) {
return capacity >> log2WordSize
}
return (maximum + (wordSize - 1 )) >> log2WordSize
}
func (rb *Bitmap ) ToDense () []uint64 {
sz := rb .DenseSize ()
if sz == 0 {
return nil
}
bitmap := make ([]uint64 , sz )
rb .WriteDenseTo (bitmap )
return bitmap
}
func FromDense (bitmap []uint64 , doCopy bool ) *Bitmap {
sz := (len (bitmap ) + bitmapContainerSize - 1 ) / bitmapContainerSize
rb := &Bitmap {
highlowcontainer : roaringArray {
containers : make ([]container , 0 , sz ),
keys : make ([]uint16 , 0 , sz ),
needCopyOnWrite : make ([]bool , 0 , sz ),
},
}
rb .FromDense (bitmap , doCopy )
return rb
}
func (rb *Bitmap ) FromDense (bitmap []uint64 , doCopy bool ) {
if len (bitmap ) == 0 {
return
}
var k uint16
const size = bitmapContainerSize
for len (bitmap ) > 0 {
hi := size
if len (bitmap ) < size {
hi = len (bitmap )
}
words := bitmap [:hi ]
count := int (popcntSlice (words ))
switch {
case count > arrayDefaultMaxSize :
c := &bitmapContainer {cardinality : count , bitmap : words }
cow := true
if doCopy || len (words ) < size {
c .bitmap = make ([]uint64 , size )
copy (c .bitmap , words )
cow = false
}
rb .highlowcontainer .appendContainer (k , c , cow )
case count > 0 :
c := &arrayContainer {content : make ([]uint16 , count )}
var pos , base int
for _ , w := range words {
for w != 0 {
t := w & -w
c .content [pos ] = uint16 (base + int (popcount (t -1 )))
pos ++
w ^= t
}
base += 64
}
rb .highlowcontainer .appendContainer (k , c , false )
}
bitmap = bitmap [hi :]
k ++
}
}
func (rb *Bitmap ) WriteDenseTo (bitmap []uint64 ) {
for i , ct := range rb .highlowcontainer .containers {
hb := uint32 (rb .highlowcontainer .keys [i ]) << 16
switch c := ct .(type ) {
case *arrayContainer :
for _ , x := range c .content {
n := int (hb | uint32 (x ))
bitmap [n >>log2WordSize ] |= uint64 (1 ) << uint (x %64 )
}
case *bitmapContainer :
copy (bitmap [int (hb )>>log2WordSize :], c .bitmap )
case *runContainer16 :
for j := range c .iv {
start := uint32 (c .iv [j ].start )
end := start + uint32 (c .iv [j ].length ) + 1
lo := int (hb |start ) >> log2WordSize
hi := int (hb |(end -1 )) >> log2WordSize
if lo == hi {
bitmap [lo ] |= (^uint64 (0 ) << uint (start %64 )) &
(^uint64 (0 ) >> (uint (-end ) % 64 ))
continue
}
bitmap [lo ] |= ^uint64 (0 ) << uint (start %64 )
for n := lo + 1 ; n < hi ; n ++ {
bitmap [n ] = ^uint64 (0 )
}
bitmap [hi ] |= ^uint64 (0 ) >> (uint (-end ) % 64 )
}
default :
panic ("unsupported container type" )
}
}
}
func (rb *Bitmap ) Checksum () uint64 {
const (
offset = 14695981039346656037
prime = 1099511628211
)
hash := uint64 (offset )
for _ , key := range rb .highlowcontainer .keys {
hash ^= uint64 (key & 0xFF )
hash *= prime
hash ^= uint64 (key >> 8 )
hash *= prime
}
for _ , c := range rb .highlowcontainer .containers {
hash ^= 0
hash *= prime
switch c := c .(type ) {
case *bitmapContainer :
for _ , val := range c .bitmap {
hash ^= val & 0xFF
hash *= prime
hash ^= (val >> 8 ) & 0xFF
hash *= prime
hash ^= (val >> 16 ) & 0xFF
hash *= prime
hash ^= (val >> 24 ) & 0xFF
hash *= prime
hash ^= (val >> 32 ) & 0xFF
hash *= prime
hash ^= (val >> 40 ) & 0xFF
hash *= prime
hash ^= (val >> 48 ) & 0xFF
hash *= prime
hash ^= (val >> 56 ) & 0xFF
hash *= prime
}
case *arrayContainer :
for _ , val := range c .content {
hash ^= uint64 (val & 0xFF )
hash *= prime
hash ^= uint64 (val >> 8 )
hash *= prime
}
case *runContainer16 :
for _ , iv := range c .iv {
hash ^= uint64 (iv .start & 0xFF )
hash *= prime
hash ^= uint64 (iv .start >> 8 )
hash *= prime
hash ^= uint64 (iv .length & 0xFF )
hash *= prime
hash ^= uint64 (iv .length >> 8 )
hash *= prime
}
default :
panic ("invalid container type" )
}
}
return hash
}
func (rb *Bitmap ) FromUnsafeBytes (data []byte , cookieHeader ...byte ) (p int64 , err error ) {
stream := internal .NewByteBuffer (data )
return rb .ReadFrom (stream )
}
func (rb *Bitmap ) ReadFrom (reader io .Reader , cookieHeader ...byte ) (p int64 , err error ) {
stream , ok := reader .(internal .ByteInput )
if !ok {
byteInputAdapter := internal .ByteInputAdapterPool .Get ().(*internal .ByteInputAdapter )
byteInputAdapter .Reset (reader )
stream = byteInputAdapter
}
p , err = rb .highlowcontainer .readFrom (stream , cookieHeader ...)
if !ok {
internal .ByteInputAdapterPool .Put (stream .(*internal .ByteInputAdapter ))
}
return
}
func (rb *Bitmap ) MustReadFrom (reader io .Reader , cookieHeader ...byte ) (p int64 , err error ) {
rb .ReadFrom (reader , cookieHeader ...)
if err := rb .Validate (); err != nil {
panic (err )
}
return
}
func (rb *Bitmap ) FromBuffer (buf []byte ) (p int64 , err error ) {
stream := internal .ByteBufferPool .Get ().(*internal .ByteBuffer )
stream .Reset (buf )
p , err = rb .highlowcontainer .readFrom (stream )
internal .ByteBufferPool .Put (stream )
return
}
func (rb *Bitmap ) RunOptimize () {
rb .highlowcontainer .runOptimize ()
}
func (rb *Bitmap ) HasRunCompression () bool {
return rb .highlowcontainer .hasRunCompression ()
}
func (rb *Bitmap ) MarshalBinary () ([]byte , error ) {
return rb .ToBytes ()
}
func (rb *Bitmap ) UnmarshalBinary (data []byte ) error {
r := bytes .NewReader (data )
_ , err := rb .ReadFrom (r )
return err
}
func NewBitmap () *Bitmap {
return &Bitmap {}
}
func New () *Bitmap {
return &Bitmap {}
}
func (rb *Bitmap ) Clear () {
rb .highlowcontainer .clear ()
}
func (rb *Bitmap ) ToBitSet () *bitset .BitSet {
return bitset .From (rb .ToDense ())
}
func FromBitSet (bitset *bitset .BitSet ) *Bitmap {
return FromDense (bitset .Bytes (), false )
}
func (rb *Bitmap ) ToArray () []uint32 {
array := make ([]uint32 , rb .GetCardinality ())
ar := rb .toArray (&array )
return *ar
}
func (rb *Bitmap ) toArray (array *[]uint32 ) *[]uint32 {
pos := 0
pos2 := 0
for pos < rb .highlowcontainer .size () {
hs := uint32 (rb .highlowcontainer .getKeyAtIndex (pos )) << 16
c := rb .highlowcontainer .getContainerAtIndex (pos )
pos ++
pos2 = c .fillLeastSignificant16bits (*array , pos2 , hs )
}
return array
}
func (rb *Bitmap ) ToExistingArray (array *[]uint32 ) *[]uint32 {
return rb .toArray (array )
}
func (rb *Bitmap ) GetSizeInBytes () uint64 {
size := uint64 (8 )
for _ , c := range rb .highlowcontainer .containers {
size += uint64 (2 ) + uint64 (c .getSizeInBytes ())
}
return size
}
func (rb *Bitmap ) GetSerializedSizeInBytes () uint64 {
return rb .highlowcontainer .serializedSizeInBytes ()
}
func BoundSerializedSizeInBytes (cardinality uint64 , universeSize uint64 ) uint64 {
contnbr := (universeSize + uint64 (65535 )) / uint64 (65536 )
if contnbr > cardinality {
contnbr = cardinality
}
headermax := 8 *contnbr + 4
if 4 > (contnbr +7 )/8 {
headermax += 4
} else {
headermax += (contnbr + 7 ) / 8
}
valsarray := uint64 (arrayContainerSizeInBytes (int (cardinality )))
valsbitmap := contnbr * uint64 (bitmapContainerSizeInBytes ())
valsbest := valsarray
if valsbest > valsbitmap {
valsbest = valsbitmap
}
return valsbest + headermax
}
type IntIterable interface {
HasNext () bool
Next () uint32
}
type IntPeekable interface {
IntIterable
PeekNext () uint32
AdvanceIfNeeded (minval uint32 )
}
type intIterator struct {
pos int
hs uint32
iter shortPeekable
highlowcontainer *roaringArray
shortIter shortIterator
runIter runIterator16
bitmapIter bitmapContainerShortIterator
}
func (ii *intIterator ) HasNext () bool {
return ii .pos < ii .highlowcontainer .size ()
}
func (ii *intIterator ) init () {
if ii .highlowcontainer .size () > ii .pos {
ii .hs = uint32 (ii .highlowcontainer .getKeyAtIndex (ii .pos )) << 16
c := ii .highlowcontainer .getContainerAtIndex (ii .pos )
switch t := c .(type ) {
case *arrayContainer :
ii .shortIter = shortIterator {t .content , 0 }
ii .iter = &ii .shortIter
case *runContainer16 :
ii .runIter = runIterator16 {rc : t , curIndex : 0 , curPosInIndex : 0 }
ii .iter = &ii .runIter
case *bitmapContainer :
ii .bitmapIter = bitmapContainerShortIterator {t , t .NextSetBit (0 )}
ii .iter = &ii .bitmapIter
}
}
}
func (ii *intIterator ) Next () uint32 {
x := uint32 (ii .iter .next ()) | ii .hs
if !ii .iter .hasNext () {
ii .pos = ii .pos + 1
ii .init ()
}
return x
}
func (ii *intIterator ) PeekNext () uint32 {
return uint32 (ii .iter .peekNext ()&maxLowBit ) | ii .hs
}
func (ii *intIterator ) AdvanceIfNeeded (minval uint32 ) {
to := minval & 0xffff0000
for ii .HasNext () && ii .hs < to {
ii .pos ++
ii .init ()
}
if ii .HasNext () && ii .hs == to {
ii .iter .advanceIfNeeded (lowbits (minval ))
if !ii .iter .hasNext () {
ii .pos ++
ii .init ()
}
}
}
type IntIterator = intIterator
func (ii *intIterator ) Initialize (a *Bitmap ) {
ii .pos = 0
ii .highlowcontainer = &a .highlowcontainer
ii .init ()
}
type intReverseIterator struct {
pos int
hs uint32
iter shortIterable
highlowcontainer *roaringArray
shortIter reverseIterator
runIter runReverseIterator16
bitmapIter reverseBitmapContainerShortIterator
}
func (ii *intReverseIterator ) HasNext () bool {
return ii .pos >= 0
}
func (ii *intReverseIterator ) init () {
if ii .pos >= 0 {
ii .hs = uint32 (ii .highlowcontainer .getKeyAtIndex (ii .pos )) << 16
c := ii .highlowcontainer .getContainerAtIndex (ii .pos )
switch t := c .(type ) {
case *arrayContainer :
ii .shortIter = reverseIterator {t .content , len (t .content ) - 1 }
ii .iter = &ii .shortIter
case *runContainer16 :
index := len (t .iv ) - 1
pos := uint16 (0 )
if index >= 0 {
pos = t .iv [index ].length
}
ii .runIter = runReverseIterator16 {rc : t , curIndex : index , curPosInIndex : pos }
ii .iter = &ii .runIter
case *bitmapContainer :
pos := -1
if t .cardinality > 0 {
pos = int (t .maximum ())
}
ii .bitmapIter = reverseBitmapContainerShortIterator {t , pos }
ii .iter = &ii .bitmapIter
}
} else {
ii .iter = nil
}
}
func (ii *intReverseIterator ) Next () uint32 {
x := uint32 (ii .iter .next ()) | ii .hs
if !ii .iter .hasNext () {
ii .pos = ii .pos - 1
ii .init ()
}
return x
}
type IntReverseIterator = intReverseIterator
func (ii *intReverseIterator ) Initialize (a *Bitmap ) {
ii .highlowcontainer = &a .highlowcontainer
ii .pos = a .highlowcontainer .size () - 1
ii .init ()
}
type ManyIntIterable interface {
NextMany (buf []uint32 ) int
NextMany64 (hs uint64 , buf []uint64 ) int
}
type manyIntIterator struct {
pos int
hs uint32
iter manyIterable
highlowcontainer *roaringArray
shortIter shortIterator
runIter runIterator16
bitmapIter bitmapContainerManyIterator
}
func (ii *manyIntIterator ) init () {
if ii .highlowcontainer .size () > ii .pos {
ii .hs = uint32 (ii .highlowcontainer .getKeyAtIndex (ii .pos )) << 16
c := ii .highlowcontainer .getContainerAtIndex (ii .pos )
switch t := c .(type ) {
case *arrayContainer :
ii .shortIter = shortIterator {t .content , 0 }
ii .iter = &ii .shortIter
case *runContainer16 :
ii .runIter = runIterator16 {rc : t , curIndex : 0 , curPosInIndex : 0 }
ii .iter = &ii .runIter
case *bitmapContainer :
ii .bitmapIter = bitmapContainerManyIterator {t , -1 , 0 }
ii .iter = &ii .bitmapIter
}
} else {
ii .iter = nil
}
}
func (ii *manyIntIterator ) NextMany (buf []uint32 ) int {
n := 0
for n < len (buf ) {
if ii .iter == nil {
break
}
moreN := ii .iter .nextMany (ii .hs , buf [n :])
n += moreN
if moreN == 0 {
ii .pos = ii .pos + 1
ii .init ()
}
}
return n
}
func (ii *manyIntIterator ) NextMany64 (hs64 uint64 , buf []uint64 ) int {
n := 0
for n < len (buf ) {
if ii .iter == nil {
break
}
hs := uint64 (ii .hs ) | hs64
moreN := ii .iter .nextMany64 (hs , buf [n :])
n += moreN
if moreN == 0 {
ii .pos = ii .pos + 1
ii .init ()
}
}
return n
}
type ManyIntIterator = manyIntIterator
func (ii *manyIntIterator ) Initialize (a *Bitmap ) {
ii .pos = 0
ii .highlowcontainer = &a .highlowcontainer
ii .init ()
}
type unsetIterator struct {
containerIndex int
nextKey int
hs uint32
iter shortPeekable
highlowcontainer *roaringArray
arrayUnsetIter arrayContainerUnsetIterator
runUnsetIter runUnsetIterator16
bitmapUnsetIter bitmapContainerUnsetIterator
emptyContainerVal uint16
start, end uint64
}
func (iui *unsetIterator ) HasNext () bool {
for iui .nextKey < 65536 && uint64 (iui .nextKey )<<16 < iui .end {
if iui .iter == nil {
if uint64 (iui .nextKey )<<16 |uint64 (iui .emptyContainerVal ) < iui .end {
return true
}
iui .nextKey ++
iui .containerIndex ++
iui .init ()
continue
}
if iui .iter .hasNext () {
nextVal := (uint64 (iui .nextKey ) << 16 ) | uint64 (iui .iter .peekNext ())
if nextVal < iui .end {
return true
}
}
iui .nextKey ++
iui .containerIndex ++
iui .init ()
}
return false
}
func (iui *unsetIterator ) init () {
if uint64 (iui .nextKey )<<16 >= iui .end {
iui .iter = nil
return
}
if iui .containerIndex >= iui .highlowcontainer .size () ||
iui .highlowcontainer .getKeyAtIndex (iui .containerIndex ) > uint16 (iui .nextKey ) {
iui .emptyContainerVal = 0
if uint64 (iui .nextKey )<<16 < iui .start && iui .start < uint64 (iui .nextKey +1 )<<16 {
iui .emptyContainerVal = uint16 (iui .start )
}
iui .iter = nil
return
}
iui .hs = uint32 (iui .nextKey ) << 16
c := iui .highlowcontainer .getContainerAtIndex (iui .containerIndex )
switch t := c .(type ) {
case *arrayContainer :
iui .arrayUnsetIter = *newArrayContainerUnsetIterator (t .content )
iui .iter = &iui .arrayUnsetIter
case *runContainer16 :
iui .runUnsetIter = *t .newRunUnsetIterator16 ()
iui .iter = &iui .runUnsetIter
case *bitmapContainer :
iui .bitmapUnsetIter = *newBitmapContainerUnsetIterator (t )
iui .iter = &iui .bitmapUnsetIter
}
if uint64 (iui .nextKey )<<16 < iui .start && iui .start < uint64 (iui .nextKey +1 )<<16 {
iui .iter .advanceIfNeeded (uint16 (iui .start ))
}
}
func (iui *unsetIterator ) Next () uint32 {
if iui .iter == nil {
x := (uint32 (iui .nextKey ) << 16 ) | uint32 (iui .emptyContainerVal )
iui .emptyContainerVal ++
if iui .emptyContainerVal == 0 || uint64 (iui .nextKey )<<16 |uint64 (iui .emptyContainerVal ) >= iui .end {
iui .nextKey ++
iui .init ()
}
return x
}
x := uint32 (iui .iter .next ()) | iui .hs
if !iui .iter .hasNext () || uint64 (iui .nextKey )<<16 |uint64 (iui .iter .peekNext ()) >= iui .end {
iui .nextKey ++
iui .containerIndex ++
iui .init ()
}
return x
}
func (iui *unsetIterator ) PeekNext () uint32 {
if !iui .HasNext () {
panic ("PeekNext() called when HasNext() returns false" )
}
if iui .iter == nil {
return (uint32 (iui .nextKey ) << 16 ) | uint32 (iui .emptyContainerVal )
}
return uint32 (iui .iter .peekNext ()&maxLowBit ) | iui .hs
}
func (iui *unsetIterator ) AdvanceIfNeeded (minval uint32 ) {
targetKey := int (minval >> 16 )
for iui .HasNext () && iui .nextKey < targetKey {
iui .nextKey ++
for iui .containerIndex < iui .highlowcontainer .size () &&
int (iui .highlowcontainer .getKeyAtIndex (iui .containerIndex )) < iui .nextKey {
iui .containerIndex ++
}
iui .init ()
}
if iui .HasNext () && iui .nextKey == targetKey {
if iui .iter != nil {
iui .iter .advanceIfNeeded (lowbits (minval ))
if !iui .iter .hasNext () || uint64 (iui .nextKey )<<16 |uint64 (iui .iter .peekNext ()) >= iui .end {
iui .nextKey ++
iui .containerIndex ++
iui .init ()
}
} else {
lowVal := lowbits (minval )
if iui .emptyContainerVal < lowVal {
iui .emptyContainerVal = lowVal
}
if uint64 (iui .nextKey )<<16 |uint64 (iui .emptyContainerVal ) >= iui .end {
iui .nextKey ++
iui .containerIndex ++
iui .init ()
}
}
}
}
func (iui *unsetIterator ) Initialize (a *Bitmap , start , end uint64 ) {
if end > 0x100000000 {
panic ("end > 0x100000000" )
}
iui .start = start
iui .end = end
iui .containerIndex = 0
iui .nextKey = int (start >> 16 )
iui .highlowcontainer = &a .highlowcontainer
for iui .containerIndex < iui .highlowcontainer .size () &&
int (iui .highlowcontainer .getKeyAtIndex (iui .containerIndex )) < iui .nextKey {
iui .containerIndex ++
}
iui .init ()
}
func (rb *Bitmap ) String () string {
var buffer bytes .Buffer
start := []byte ("{" )
buffer .Write (start )
i := rb .Iterator ()
counter := 0
if i .HasNext () {
counter = counter + 1
buffer .WriteString (strconv .FormatInt (int64 (i .Next ()), 10 ))
}
for i .HasNext () {
buffer .WriteString ("," )
counter = counter + 1
if counter > 0x40000 {
buffer .WriteString ("..." )
break
}
buffer .WriteString (strconv .FormatInt (int64 (i .Next ()), 10 ))
}
buffer .WriteString ("}" )
return buffer .String ()
}
func (rb *Bitmap ) Iterate (cb func (x uint32 ) bool ) {
for i := 0 ; i < rb .highlowcontainer .size (); i ++ {
hs := uint32 (rb .highlowcontainer .getKeyAtIndex (i )) << 16
c := rb .highlowcontainer .getContainerAtIndex (i )
var shouldContinue bool
switch t := c .(type ) {
case *arrayContainer :
shouldContinue = t .iterate (func (x uint16 ) bool {
return cb (uint32 (x ) | hs )
})
case *runContainer16 :
shouldContinue = t .iterate (func (x uint16 ) bool {
return cb (uint32 (x ) | hs )
})
case *bitmapContainer :
shouldContinue = t .iterate (func (x uint16 ) bool {
return cb (uint32 (x ) | hs )
})
}
if !shouldContinue {
break
}
}
}
func (rb *Bitmap ) Iterator () IntPeekable {
p := new (intIterator )
p .Initialize (rb )
return p
}
func (rb *Bitmap ) ReverseIterator () IntIterable {
p := new (intReverseIterator )
p .Initialize (rb )
return p
}
func (rb *Bitmap ) ManyIterator () ManyIntIterable {
p := new (manyIntIterator )
p .Initialize (rb )
return p
}
func (rb *Bitmap ) UnsetIterator (start , end uint64 ) IntPeekable {
p := new (unsetIterator )
p .Initialize (rb , start , end )
return p
}
func (rb *Bitmap ) Clone () *Bitmap {
ptr := new (Bitmap )
ptr .highlowcontainer = *rb .highlowcontainer .clone ()
return ptr
}
func (rb *Bitmap ) Minimum () uint32 {
if len (rb .highlowcontainer .containers ) == 0 {
panic ("Empty bitmap" )
}
return uint32 (rb .highlowcontainer .containers [0 ].minimum ()) | (uint32 (rb .highlowcontainer .keys [0 ]) << 16 )
}
func (rb *Bitmap ) Maximum () uint32 {
if len (rb .highlowcontainer .containers ) == 0 {
panic ("Empty bitmap" )
}
lastindex := len (rb .highlowcontainer .containers ) - 1
return uint32 (rb .highlowcontainer .containers [lastindex ].maximum ()) | (uint32 (rb .highlowcontainer .keys [lastindex ]) << 16 )
}
func (rb *Bitmap ) Contains (x uint32 ) bool {
hb := highbits (x )
c := rb .highlowcontainer .getContainer (hb )
return c != nil && c .contains (lowbits (x ))
}
func (rb *Bitmap ) ContainsInt (x int ) bool {
return rb .Contains (uint32 (x ))
}
func (rb *Bitmap ) Equals (o interface {}) bool {
srb , ok := o .(*Bitmap )
if ok {
return srb .highlowcontainer .equals (rb .highlowcontainer )
}
return false
}
func AddOffset (x *Bitmap , offset uint32 ) (answer *Bitmap ) {
return AddOffset64 (x , int64 (offset ))
}
func AddOffset64 (x *Bitmap , offset int64 ) (answer *Bitmap ) {
var containerOffset64 int64
if offset < 0 {
containerOffset64 = (offset - (1 << 16 ) + 1 ) / (1 << 16 )
} else {
containerOffset64 = offset >> 16
}
answer = New ()
if containerOffset64 >= (1 <<16 ) || containerOffset64 < -(1 <<16 ) {
return answer
}
containerOffset := int32 (containerOffset64 )
inOffset := (uint16 )(offset - containerOffset64 *(1 <<16 ))
if inOffset == 0 {
for pos := 0 ; pos < x .highlowcontainer .size (); pos ++ {
key := int32 (x .highlowcontainer .getKeyAtIndex (pos ))
key += containerOffset
if key >= 0 && key <= MaxUint16 {
c := x .highlowcontainer .getContainerAtIndex (pos ).clone ()
answer .highlowcontainer .appendContainer (uint16 (key ), c , false )
}
}
} else {
for pos := 0 ; pos < x .highlowcontainer .size (); pos ++ {
key := int32 (x .highlowcontainer .getKeyAtIndex (pos ))
key += containerOffset
if key +1 < 0 || key > MaxUint16 {
continue
}
c := x .highlowcontainer .getContainerAtIndex (pos )
lo , hi := c .addOffset (inOffset )
if lo != nil && key >= 0 {
curSize := answer .highlowcontainer .size ()
lastkey := int32 (0 )
if curSize > 0 {
lastkey = int32 (answer .highlowcontainer .getKeyAtIndex (curSize - 1 ))
}
if curSize > 0 && lastkey == key {
prev := answer .highlowcontainer .getContainerAtIndex (curSize - 1 )
orresult := prev .ior (lo )
answer .highlowcontainer .setContainerAtIndex (curSize -1 , orresult )
} else {
answer .highlowcontainer .appendContainer (uint16 (key ), lo , false )
}
}
if hi != nil && key +1 <= MaxUint16 {
answer .highlowcontainer .appendContainer (uint16 (key +1 ), hi , false )
}
}
}
return answer
}
func (rb *Bitmap ) Add (x uint32 ) {
hb := highbits (x )
ra := &rb .highlowcontainer
i := ra .getIndex (hb )
if i >= 0 {
var c container
c = ra .getWritableContainerAtIndex (i ).iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
newac := newArrayContainer ()
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , hb , newac .iaddReturnMinimized (lowbits (x )))
}
}
func (rb *Bitmap ) addwithptr (x uint32 ) (int , container ) {
hb := highbits (x )
ra := &rb .highlowcontainer
i := ra .getIndex (hb )
var c container
if i >= 0 {
c = ra .getWritableContainerAtIndex (i ).iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , c )
return i , c
}
newac := newArrayContainer ()
c = newac .iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , hb , c )
return -i - 1 , c
}
func (rb *Bitmap ) CheckedAdd (x uint32 ) bool {
hb := highbits (x )
i := rb .highlowcontainer .getIndex (hb )
if i >= 0 {
C := rb .highlowcontainer .getWritableContainerAtIndex (i )
oldcard := C .getCardinality ()
C = C .iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , C )
return C .getCardinality () > oldcard
}
newac := newArrayContainer ()
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , hb , newac .iaddReturnMinimized (lowbits (x )))
return true
}
func (rb *Bitmap ) AddInt (x int ) {
rb .Add (uint32 (x ))
}
func (rb *Bitmap ) Remove (x uint32 ) {
hb := highbits (x )
i := rb .highlowcontainer .getIndex (hb )
if i >= 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).iremoveReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , c )
if rb .highlowcontainer .getContainerAtIndex (i ).isEmpty () {
rb .highlowcontainer .removeAtIndex (i )
}
}
}
func (rb *Bitmap ) CheckedRemove (x uint32 ) bool {
hb := highbits (x )
i := rb .highlowcontainer .getIndex (hb )
if i >= 0 {
C := rb .highlowcontainer .getWritableContainerAtIndex (i )
oldcard := C .getCardinality ()
C = C .iremoveReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , C )
if rb .highlowcontainer .getContainerAtIndex (i ).isEmpty () {
rb .highlowcontainer .removeAtIndex (i )
return true
}
return C .getCardinality () < oldcard
}
return false
}
func (rb *Bitmap ) IsEmpty () bool {
return rb .highlowcontainer .size () == 0
}
func (rb *Bitmap ) GetCardinality () uint64 {
size := uint64 (0 )
for _ , c := range rb .highlowcontainer .containers {
size += uint64 (c .getCardinality ())
}
return size
}
func (rb *Bitmap ) Rank (x uint32 ) uint64 {
size := uint64 (0 )
for i := 0 ; i < rb .highlowcontainer .size (); i ++ {
key := rb .highlowcontainer .getKeyAtIndex (i )
if key > highbits (x ) {
return size
}
if key < highbits (x ) {
size += uint64 (rb .highlowcontainer .getContainerAtIndex (i ).getCardinality ())
} else {
return size + uint64 (rb .highlowcontainer .getContainerAtIndex (i ).rank (lowbits (x )))
}
}
return size
}
func (rb *Bitmap ) CardinalityInRange (start , end uint64 ) uint64 {
if start >= end {
return 0
}
if end > MaxUint32 +1 {
end = MaxUint32 + 1
}
hbStart := highbits (uint32 (start ))
hbEnd := highbits (uint32 (end - 1 ))
size := rb .highlowcontainer .size ()
startIdx := rb .highlowcontainer .getIndex (hbStart )
if startIdx < 0 {
startIdx = -startIdx - 1
}
if startIdx >= size {
return 0
}
result := uint64 (0 )
if hbStart == hbEnd {
key := rb .highlowcontainer .getKeyAtIndex (startIdx )
if key == hbStart {
lo := uint (lowbits (uint32 (start )))
hi := uint (lowbits (uint32 (end -1 ))) + 1
return uint64 (rb .highlowcontainer .getContainerAtIndex (startIdx ).getCardinalityInRange (lo , hi ))
}
return 0
}
key := rb .highlowcontainer .getKeyAtIndex (startIdx )
if key == hbStart {
lo := uint (lowbits (uint32 (start )))
result += uint64 (rb .highlowcontainer .getContainerAtIndex (startIdx ).getCardinalityInRange (lo , 1 <<16 ))
startIdx ++
}
endIdx := rb .highlowcontainer .getIndex (hbEnd )
endPresent := endIdx >= 0
if endIdx < 0 {
endIdx = -endIdx - 2
}
for i := startIdx ; i <= endIdx ; i ++ {
if endPresent && i == endIdx {
break
}
result += uint64 (rb .highlowcontainer .getContainerAtIndex (i ).getCardinality ())
}
if endPresent {
hi := uint (lowbits (uint32 (end -1 ))) + 1
result += uint64 (rb .highlowcontainer .getContainerAtIndex (endIdx ).getCardinalityInRange (0 , hi ))
}
return result
}
func (rb *Bitmap ) Select (x uint32 ) (uint32 , error ) {
remaining := x
for i := 0 ; i < rb .highlowcontainer .size (); i ++ {
c := rb .highlowcontainer .getContainerAtIndex (i )
card := uint32 (c .getCardinality ())
if remaining >= card {
remaining -= card
} else {
key := rb .highlowcontainer .getKeyAtIndex (i )
return uint32 (key )<<16 + uint32 (c .selectInt (uint16 (remaining ))), nil
}
}
return 0 , fmt .Errorf ("cannot find %dth integer in a bitmap with only %d items" , x , rb .GetCardinality ())
}
func (rb *Bitmap ) And (x2 *Bitmap ) {
pos1 := 0
pos2 := 0
intersectionsize := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getWritableContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
diff := c1 .iand (c2 )
if !diff .isEmpty () {
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , diff , false )
intersectionsize ++
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
rb .highlowcontainer .resize (intersectionsize )
}
func (rb *Bitmap ) OrCardinality (x2 *Bitmap ) uint64 {
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
answer := uint64 (0 )
main :
for {
if (pos1 < length1 ) && (pos2 < length2 ) {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
answer += uint64 (rb .highlowcontainer .getContainerAtIndex (pos1 ).getCardinality ())
pos1 ++
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 > s2 {
answer += uint64 (x2 .highlowcontainer .getContainerAtIndex (pos2 ).getCardinality ())
pos2 ++
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
answer += uint64 (rb .highlowcontainer .getContainerAtIndex (pos1 ).or (x2 .highlowcontainer .getContainerAtIndex (pos2 )).getCardinality ())
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
for ; pos1 < length1 ; pos1 ++ {
answer += uint64 (rb .highlowcontainer .getContainerAtIndex (pos1 ).getCardinality ())
}
for ; pos2 < length2 ; pos2 ++ {
answer += uint64 (x2 .highlowcontainer .getContainerAtIndex (pos2 ).getCardinality ())
}
return answer
}
func (rb *Bitmap ) AndCardinality (x2 *Bitmap ) uint64 {
pos1 := 0
pos2 := 0
answer := uint64 (0 )
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
answer += uint64 (c1 .andCardinality (c2 ))
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
return answer
}
func (rb *Bitmap ) IntersectsWithInterval (x , y uint64 ) bool {
if x >= y {
return false
}
if x > MaxUint32 {
return false
}
it := intIterator {}
it .Initialize (rb )
it .AdvanceIfNeeded (uint32 (x ))
if !it .HasNext () {
return false
}
if uint64 (it .Next ()) >= y {
return false
}
return true
}
func (rb *Bitmap ) Intersects (x2 *Bitmap ) bool {
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
if c1 .intersects (c2 ) {
return true
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
return false
}
func (rb *Bitmap ) Xor (x2 *Bitmap ) {
if rb == x2 {
rb .Clear ()
return
}
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
for {
if (pos1 < length1 ) && (pos2 < length2 ) {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break
}
} else if s1 > s2 {
rb .highlowcontainer .insertNewKeyValueAt (pos1 , x2 .highlowcontainer .getKeyAtIndex (pos2 ), x2 .highlowcontainer .getContainerAtIndex (pos2 ).clone ())
length1 ++
pos1 ++
pos2 ++
} else {
c := rb .highlowcontainer .getWritableContainerAtIndex (pos1 ).ixor (x2 .highlowcontainer .getContainerAtIndex (pos2 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (pos1 , c )
pos1 ++
} else {
rb .highlowcontainer .removeAtIndex (pos1 )
length1 --
}
pos2 ++
}
} else {
break
}
}
if pos1 == length1 {
rb .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
}
}
func (rb *Bitmap ) Or (x2 *Bitmap ) {
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for (pos1 < length1 ) && (pos2 < length2 ) {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
pos1 ++
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 > s2 {
rb .highlowcontainer .insertNewKeyValueAt (pos1 , s2 , x2 .highlowcontainer .getContainerAtIndex (pos2 ).clone ())
pos1 ++
length1 ++
pos2 ++
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
newcont := rb .highlowcontainer .getUnionedWritableContainer (pos1 , x2 .highlowcontainer .getContainerAtIndex (pos2 ))
rb .highlowcontainer .replaceKeyAndContainerAtIndex (pos1 , s1 , newcont , false )
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
}
if pos1 == length1 {
rb .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
}
}
func (rb *Bitmap ) AndNot (x2 *Bitmap ) {
if rb == x2 {
rb .Clear ()
return
}
pos1 := 0
pos2 := 0
intersectionsize := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getWritableContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
diff := c1 .iandNot (c2 )
if !diff .isEmpty () {
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , diff , false )
intersectionsize ++
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
mustCopyOnWrite := rb .highlowcontainer .needsCopyOnWrite (pos1 )
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , c1 , mustCopyOnWrite )
intersectionsize ++
pos1 ++
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
for pos1 < length1 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
mustCopyOnWrite := rb .highlowcontainer .needsCopyOnWrite (pos1 )
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , c1 , mustCopyOnWrite )
intersectionsize ++
pos1 ++
}
rb .highlowcontainer .resize (intersectionsize )
}
func Or (x1 , x2 *Bitmap ) *Bitmap {
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for (pos1 < length1 ) && (pos2 < length2 ) {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
answer .highlowcontainer .appendCopy (x1 .highlowcontainer , pos1 )
pos1 ++
if pos1 == length1 {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 > s2 {
answer .highlowcontainer .appendCopy (x2 .highlowcontainer , pos2 )
pos2 ++
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
answer .highlowcontainer .appendContainer (s1 , x1 .highlowcontainer .getContainerAtIndex (pos1 ).or (x2 .highlowcontainer .getContainerAtIndex (pos2 )), false )
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
}
if pos1 == length1 {
answer .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
} else if pos2 == length2 {
answer .highlowcontainer .appendCopyMany (x1 .highlowcontainer , pos1 , length1 )
}
return answer
}
func And (x1 , x2 *Bitmap ) *Bitmap {
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for pos1 < length1 && pos2 < length2 {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
C := x1 .highlowcontainer .getContainerAtIndex (pos1 )
C = C .and (x2 .highlowcontainer .getContainerAtIndex (pos2 ))
if !C .isEmpty () {
answer .highlowcontainer .appendContainer (s1 , C , false )
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = x1 .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
}
return answer
}
func Xor (x1 , x2 *Bitmap ) *Bitmap {
if x1 == x2 {
return NewBitmap ()
}
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
for {
if (pos1 < length1 ) && (pos2 < length2 ) {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
if s1 < s2 {
answer .highlowcontainer .appendCopy (x1 .highlowcontainer , pos1 )
pos1 ++
} else if s1 > s2 {
answer .highlowcontainer .appendCopy (x2 .highlowcontainer , pos2 )
pos2 ++
} else {
c := x1 .highlowcontainer .getContainerAtIndex (pos1 ).xor (x2 .highlowcontainer .getContainerAtIndex (pos2 ))
if !c .isEmpty () {
answer .highlowcontainer .appendContainer (s1 , c , false )
}
pos1 ++
pos2 ++
}
} else {
break
}
}
if pos1 == length1 {
answer .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
} else if pos2 == length2 {
answer .highlowcontainer .appendCopyMany (x1 .highlowcontainer , pos1 , length1 )
}
return answer
}
func AndNot (x1 , x2 *Bitmap ) *Bitmap {
if x1 == x2 {
return NewBitmap ()
}
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
answer .highlowcontainer .appendCopy (x1 .highlowcontainer , pos1 )
pos1 ++
if pos1 == length1 {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 == s2 {
c1 := x1 .highlowcontainer .getContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
diff := c1 .andNot (c2 )
if !diff .isEmpty () {
answer .highlowcontainer .appendContainer (s1 , diff , false )
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
if pos2 == length2 {
answer .highlowcontainer .appendCopyMany (x1 .highlowcontainer , pos1 , length1 )
}
return answer
}
func (rb *Bitmap ) AddMany (dat []uint32 ) {
if len (dat ) == 0 {
return
}
prev := dat [0 ]
idx , c := rb .addwithptr (prev )
for _ , i := range dat [1 :] {
if highbits (prev ) == highbits (i ) {
c = c .iaddReturnMinimized (lowbits (i ))
rb .highlowcontainer .setContainerAtIndex (idx , c )
} else {
idx , c = rb .addwithptr (i )
}
prev = i
}
}
func BitmapOf (dat ...uint32 ) *Bitmap {
ans := NewBitmap ()
ans .AddMany (dat )
return ans
}
func (rb *Bitmap ) Flip (rangeStart , rangeEnd uint64 ) {
if rangeEnd > MaxUint32 +1 {
panic ("rangeEnd > MaxUint32+1" )
}
if rangeStart > MaxUint32 +1 {
panic ("rangeStart > MaxUint32+1" )
}
if rangeStart >= rangeEnd {
return
}
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
var max uint32 = maxLowBit
for hb := hbStart ; hb <= hbLast ; hb ++ {
var containerStart uint32
if hb == hbStart {
containerStart = lbStart
}
containerLast := max
if hb == hbLast {
containerLast = lbLast
}
i := rb .highlowcontainer .getIndex (uint16 (hb ))
if i >= 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).inot (int (containerStart ), int (containerLast )+1 )
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
rb .highlowcontainer .removeAtIndex (i )
}
} else {
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , uint16 (hb ), rangeOfOnes (int (containerStart ), int (containerLast )))
}
}
}
func (rb *Bitmap ) FlipInt (rangeStart , rangeEnd int ) {
rb .Flip (uint64 (rangeStart ), uint64 (rangeEnd ))
}
func (rb *Bitmap ) AddRange (rangeStart , rangeEnd uint64 ) {
if rangeStart >= rangeEnd {
return
}
if rangeEnd -1 > MaxUint32 {
panic ("rangeEnd-1 > MaxUint32" )
}
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
var max uint32 = maxLowBit
for hb := hbStart ; hb <= hbLast ; hb ++ {
containerStart := uint32 (0 )
if hb == hbStart {
containerStart = lbStart
}
containerLast := max
if hb == hbLast {
containerLast = lbLast
}
i := rb .highlowcontainer .getIndex (uint16 (hb ))
if i >= 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).iaddRange (int (containerStart ), int (containerLast )+1 )
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , uint16 (hb ), rangeOfOnes (int (containerStart ), int (containerLast )))
}
}
}
func (rb *Bitmap ) RemoveRange (rangeStart , rangeEnd uint64 ) {
if rangeStart >= rangeEnd {
return
}
if rangeEnd -1 > MaxUint32 {
rangeEnd = uint64 (0x100000000 )
}
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
var max uint32 = maxLowBit
if hbStart == hbLast {
i := rb .highlowcontainer .getIndex (uint16 (hbStart ))
if i < 0 {
return
}
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).iremoveRange (int (lbStart ), int (lbLast +1 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
rb .highlowcontainer .removeAtIndex (i )
}
return
}
ifirst := rb .highlowcontainer .getIndex (uint16 (hbStart ))
ilast := rb .highlowcontainer .getIndex (uint16 (hbLast ))
if ifirst >= 0 {
if lbStart != 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (ifirst ).iremoveRange (int (lbStart ), int (max +1 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (ifirst , c )
ifirst ++
}
}
} else {
ifirst = -ifirst - 1
}
if ilast >= 0 {
if lbLast != max {
c := rb .highlowcontainer .getWritableContainerAtIndex (ilast ).iremoveRange (int (0 ), int (lbLast +1 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (ilast , c )
} else {
ilast ++
}
} else {
ilast ++
}
} else {
ilast = -ilast - 1
}
rb .highlowcontainer .removeIndexRange (ifirst , ilast )
}
func Flip (bm *Bitmap , rangeStart , rangeEnd uint64 ) *Bitmap {
if rangeStart >= rangeEnd {
return bm .Clone ()
}
if rangeStart > MaxUint32 {
panic ("rangeStart > MaxUint32" )
}
if rangeEnd -1 > MaxUint32 {
panic ("rangeEnd-1 > MaxUint32" )
}
answer := NewBitmap ()
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
answer .highlowcontainer .appendCopiesUntil (bm .highlowcontainer , uint16 (hbStart ))
var max uint32 = maxLowBit
for hb := hbStart ; hb <= hbLast ; hb ++ {
var containerStart uint32
if hb == hbStart {
containerStart = lbStart
}
containerLast := max
if hb == hbLast {
containerLast = lbLast
}
i := bm .highlowcontainer .getIndex (uint16 (hb ))
j := answer .highlowcontainer .getIndex (uint16 (hb ))
if i >= 0 {
c := bm .highlowcontainer .getContainerAtIndex (i ).not (int (containerStart ), int (containerLast )+1 )
if !c .isEmpty () {
answer .highlowcontainer .insertNewKeyValueAt (-j -1 , uint16 (hb ), c )
}
} else {
answer .highlowcontainer .insertNewKeyValueAt (-j -1 , uint16 (hb ),
rangeOfOnes (int (containerStart ), int (containerLast )))
}
}
answer .highlowcontainer .appendCopiesAfter (bm .highlowcontainer , uint16 (hbLast ))
return answer
}
func (rb *Bitmap ) SetCopyOnWrite (val bool ) {
rb .highlowcontainer .copyOnWrite = val
}
func (rb *Bitmap ) GetCopyOnWrite () (val bool ) {
return rb .highlowcontainer .copyOnWrite
}
func (rb *Bitmap ) CloneCopyOnWriteContainers () {
rb .highlowcontainer .cloneCopyOnWriteContainers ()
}
func (rb *Bitmap ) NextValue (target uint32 ) int64 {
originalKey := highbits (target )
query := lowbits (target )
var nextValue int64
nextValue = -1
containerIndex := rb .highlowcontainer .advanceUntil (originalKey , -1 )
for containerIndex < rb .highlowcontainer .size () && nextValue == -1 {
containerKey := rb .highlowcontainer .getKeyAtIndex (containerIndex )
container := rb .highlowcontainer .getContainer (containerKey )
var responseBit int64
if containerKey > originalKey {
bit , err := container .safeMinimum ()
if err == nil {
responseBit = -1
}
responseBit = int64 (bit )
} else {
responseBit = int64 (container .nextValue (query ))
}
if responseBit == -1 {
nextValue = -1
} else {
nextValue = int64 (combineLoHi32 (uint32 (responseBit ), uint32 (containerKey )))
}
containerIndex ++
}
return nextValue
}
func (rb *Bitmap ) PreviousValue (target uint32 ) int64 {
if rb .IsEmpty () {
return -1
}
originalKey := highbits (target )
query := lowbits (target )
var prevValue int64
prevValue = -1
containerIndex := rb .highlowcontainer .advanceUntil (originalKey , -1 )
if containerIndex == rb .highlowcontainer .size () {
return int64 (rb .Maximum ())
}
if rb .highlowcontainer .getKeyAtIndex (containerIndex ) > originalKey {
containerIndex --
}
for containerIndex != -1 && prevValue == -1 {
containerKey := rb .highlowcontainer .getKeyAtIndex (containerIndex )
container := rb .highlowcontainer .getContainer (containerKey )
var responseBit int
if containerKey < originalKey {
bit , err := container .safeMaximum ()
if err == nil {
responseBit = -1
}
responseBit = int (bit )
} else {
responseBit = container .previousValue (query )
}
if responseBit == -1 {
prevValue = -1
} else {
prevValue = int64 (combineLoHi32 (uint32 (responseBit ), uint32 (containerKey )))
}
containerIndex --
}
return prevValue
}
func (rb *Bitmap ) NextAbsentValue (target uint32 ) int64 {
originalKey := highbits (target )
query := lowbits (target )
var nextValue int64
nextValue = -1
containerIndex := rb .highlowcontainer .advanceUntil (originalKey , -1 )
if containerIndex == rb .highlowcontainer .size () {
return int64 (target )
}
containerKey := rb .highlowcontainer .getKeyAtIndex (containerIndex )
keyspace := uint32 (containerKey ) << 16
if target < keyspace {
return int64 (target )
}
container := rb .highlowcontainer .getContainer (containerKey )
nextValue = int64 (container .nextAbsentValue (query ))
for {
if nextValue != (1 << 16 ) {
return int64 (combineLoHi32 (uint32 (nextValue ), keyspace ))
}
if containerIndex == rb .highlowcontainer .size ()-1 {
val , err := container .safeMaximum ()
if err == nil {
return -1
}
return int64 (val ) + 1
}
containerIndex ++
nextContainerKey := rb .highlowcontainer .getKeyAtIndex (containerIndex )
if containerKey < nextContainerKey {
return int64 (containerKey +1 ) << 16
}
containerKey = nextContainerKey
container = rb .highlowcontainer .getContainer (containerKey )
nextValue = int64 (container .nextAbsentValue (0 ))
}
}
func (rb *Bitmap ) PreviousAbsentValue (target uint32 ) int64 {
originalKey := highbits (target )
query := lowbits (target )
var prevValue int64
prevValue = -1
containerIndex := rb .highlowcontainer .advanceUntil (originalKey , -1 )
if containerIndex == rb .highlowcontainer .size () {
return int64 (target )
}
if containerIndex == -1 {
return int64 (target )
}
containerKey := rb .highlowcontainer .getKeyAtIndex (containerIndex )
keyspace := uint32 (containerKey ) << 16
if target < keyspace {
return int64 (target )
}
container := rb .highlowcontainer .getContainer (containerKey )
prevValue = int64 (container .previousAbsentValue (query ))
for {
if prevValue != -1 {
return int64 (combineLoHi32 (uint32 (prevValue ), keyspace ))
}
if containerIndex == 0 {
val , err := container .safeMinimum ()
if err == nil {
return -1
}
return int64 (val ) - 1
}
containerIndex --
nextContainerKey := rb .highlowcontainer .getKeyAtIndex (containerIndex )
if nextContainerKey < containerKey -1 {
return (int64 (containerKey ) << 16 ) - 1
}
containerKey = nextContainerKey
container = rb .highlowcontainer .getContainer (containerKey )
highestPossible16 := (1 << 16 ) - 1
prevValue = int64 (container .previousAbsentValue (uint16 (highestPossible16 )))
}
}
func FlipInt (bm *Bitmap , rangeStart , rangeEnd int ) *Bitmap {
return Flip (bm , uint64 (rangeStart ), uint64 (rangeEnd ))
}
type Statistics struct {
Cardinality uint64
Containers uint64
ArrayContainers uint64
ArrayContainerBytes uint64
ArrayContainerValues uint64
BitmapContainers uint64
BitmapContainerBytes uint64
BitmapContainerValues uint64
RunContainers uint64
RunContainerBytes uint64
RunContainerValues uint64
}
func (rb *Bitmap ) Stats () Statistics {
stats := Statistics {}
stats .Containers = uint64 (len (rb .highlowcontainer .containers ))
for _ , c := range rb .highlowcontainer .containers {
stats .Cardinality += uint64 (c .getCardinality ())
switch c .(type ) {
case *arrayContainer :
stats .ArrayContainers ++
stats .ArrayContainerBytes += uint64 (c .getSizeInBytes ())
stats .ArrayContainerValues += uint64 (c .getCardinality ())
case *bitmapContainer :
stats .BitmapContainers ++
stats .BitmapContainerBytes += uint64 (c .getSizeInBytes ())
stats .BitmapContainerValues += uint64 (c .getCardinality ())
case *runContainer16 :
stats .RunContainers ++
stats .RunContainerBytes += uint64 (c .getSizeInBytes ())
stats .RunContainerValues += uint64 (c .getCardinality ())
}
}
return stats
}
func (rb *Bitmap ) Describe () {
fmt .Printf ("Bitmap with %d containers:\n" , len (rb .highlowcontainer .containers ))
for i , c := range rb .highlowcontainer .containers {
key := rb .highlowcontainer .keys [i ]
shared := ""
if rb .highlowcontainer .needCopyOnWrite [i ] {
shared = " (shared)"
}
switch c .(type ) {
case *arrayContainer :
fmt .Printf (" Container %d (key %d): array, cardinality %d%s\n" , i , key , c .getCardinality (), shared )
case *bitmapContainer :
fmt .Printf (" Container %d (key %d): bitmap, cardinality %d%s\n" , i , key , c .getCardinality (), shared )
case *runContainer16 :
fmt .Printf (" Container %d (key %d): run, cardinality %d%s\n" , i , key , c .getCardinality (), shared )
default :
fmt .Printf (" Container %d (key %d): unknown type, cardinality %d%s\n" , i , key , c .getCardinality (), shared )
}
}
valid := rb .Validate ()
if valid != nil {
fmt .Printf (" Bitmap is INVALID: %v\n" , valid )
} else {
fmt .Printf (" Bitmap is valid\n" )
}
}
func (rb *Bitmap ) Validate () error {
return rb .highlowcontainer .validate ()
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .